﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Data;
using System.Data.Objects;
using Fujitsu.JiraAnalysis.Common;

namespace Fujitsu.JiraAnalysis.DAL
{
    public class ProjectStorage
    {
        public IEventLog EventLog = new EventLogWrapper();

        public double GetUserWorkTimeByIssue(int userId, int issueId)
        {
            List<Worklog> workLogs;

            using (var db = new JiraAnalysisDBEntities())
            {
                var user = db.User.FirstOrDefault(u => u.ID == userId);
                if (user == null)
                    throw new UserNotFoundException();

                var issue = db.Issue.FirstOrDefault(i => i.ID == issueId);
                if (issue == null)
                    throw new IssueNotFoundException();

                workLogs = (from w in db.Worklog
                            where w.IssueID == issue.ID
                            select w).ToList();
            }

            return workLogs.Aggregate((double)0, (c, s) => c + (double)s.TimeWorked);
        }

        public List<Project> GetProjectsToSynchronize()
        {
            using (var db = new JiraAnalysisDBEntities())
            {
                try
                {
                    return (from p in db.Project.Include("User")
                            where p.IsToSynchronize && !p.IsNeedCheck
                            select p).ToList();
                }
                catch (EntityException ex)
                {
                    EventLogger.CreateInstance(EventLog).LogWriteError(string.Concat("Can't get projects from DB.", Environment.NewLine, ex.Message));
                    return new List<Project>();
                }
            }
        }

        public List<Project> GetAllProjects(string jiraUrl)
        {
            using (var db = new JiraAnalysisDBEntities())
            {
                try
                {
                    return db.Project.Where(p => p.JiraUrl == jiraUrl).ToList();
                }
                catch (EntityException ex)
                {
                    EventLogger.CreateInstance(EventLog).LogWriteError(string.Concat("Can't get projects from DB.", Environment.NewLine, ex.Message));
                    return new List<Project>();
                }
            }
        }

        public List<Project> GetAllProjects(int startRowIndex, int maximumRows)
        {
            using (var db = new JiraAnalysisDBEntities())
            {
                try
                {
                    return (from p in db.Project
                            orderby p.Name
                            select p).Skip(startRowIndex).Take(maximumRows).ToList();
                }
                catch (EntityException ex)
                {
                    EventLogger.CreateInstance(EventLog).LogWriteError(string.Concat("Can't get projects from DB.", Environment.NewLine, ex.Message));
                    return new List<Project>();
                }
            }
        }

        public int GetAllProjectsCount()
        {
            using (var db = new JiraAnalysisDBEntities())
            {
                try
                {
                    return db.Project.Count();
                }
                catch (EntityException ex)
                {
                    EventLogger.CreateInstance(EventLog).LogWriteError(string.Concat("Can't get projects' count from DB.", Environment.NewLine, ex.Message));
                    return 0;
                }
            }
        }

        public List<Project> GetAllProjects()
        {
            using (var db = new JiraAnalysisDBEntities())
            {
                try
                {
                    return db.Project.ToList();
                }
                catch (EntityException ex)
                {
                    EventLogger.CreateInstance(EventLog).LogWriteError(string.Concat("Can't get projects from DB.", Environment.NewLine, ex.Message));
                    return new List<Project>();
                }
            }
        }

        public void UpdateProjectLead(int projectId, int leadId)
        {
            using (var db = new JiraAnalysisDBEntities())
            {
                var projectToUpdate = (from p in db.Project
                                       where p.ID == projectId
                                       select p).FirstOrDefault();
                if (projectToUpdate != null)
                {
                    projectToUpdate.LeadID = leadId;
                }
                try
                {
                    db.SaveChanges();
                }
                catch (OptimisticConcurrencyException)
                {
                    db.Refresh(RefreshMode.ClientWins, projectToUpdate);
                    db.SaveChanges();
                }
            }
        }

        public void SetNeedCheckProject(Project project)
        {
            using (var db = new JiraAnalysisDBEntities())
            {
                var projectToCheck = (from p in db.Project
                                      where p.ID == project.ID
                                      select p).FirstOrDefault();
                if (projectToCheck != null)
                {
                    projectToCheck.IsNeedCheck = true;
                    db.SaveChanges();
                }
            }
        }

        public bool AddProject(string jiraUrl, string jiraLogin, string jiraPassword, string projectKey, string projectName, string description, bool isToSynchronize, out int projectId)
        {
            using (var db = new JiraAnalysisDBEntities())
            {
                var match = db.Project.Any(p => p.JiraUrl == jiraUrl && p.ProjectKey == projectKey);
                if (!match)
                {
                    var project = new Project
                    {
                        JiraUrl = jiraUrl,
                        JiraLogin = jiraLogin,
                        JiraPassword = jiraPassword,
                        IsToSynchronize = isToSynchronize,
                        IsNeedCheck = true,
                        ProjectKey = projectKey,
                        Name = projectName,
                        Description = description
                    };

                    try
                    {
                        db.Project.AddObject(project);
                        db.SaveChanges();
                        projectId = project.ID;
                        return true;
                    }
                    catch (OptimisticConcurrencyException)
                    {
                        db.Refresh(RefreshMode.ClientWins, project);
                        db.SaveChanges();
                    }
                    catch (Exception ex)
                    {
                        EventLogger.CreateInstance(EventLog).LogWriteError(string.Format("Can't add project '{0}'{1}{2}", project.ProjectKey, Environment.NewLine, ex.Message));
                    }
                    projectId = 0;
                    return false;
                }
                projectId = 0;
                return false;
            }
        }

        public void DeleteProject(int projectId)
        {
            var issueStorage = new IssueStorage();
            issueStorage.DeleteIssuesOfProject(projectId);

            var versionStorage = new VersionStorage();
            versionStorage.DeleteVersionsOfProject(projectId);

            var issueTypeMappingStorage = new IssuesTypeStorage();
            issueTypeMappingStorage.DeleteIssueTypeMappingOfProject(projectId);

            var priorityMappingStorage = new PriorityStorage();
            priorityMappingStorage.DeletePriorityMappingOfProject(projectId);

            var statusMappingStorage = new StatusStorage();
            statusMappingStorage.DeleteStatusMappingsOfProject(projectId);

            var resolutionMappingStorage = new ResolutionStorage();
            resolutionMappingStorage.DeleteResolutionMappingOfProject(projectId);

            using (var db = new JiraAnalysisDBEntities())
            {
                var project = db.Project.Where(p => p.ID == projectId).FirstOrDefault();
                if (project == null)
                    return;

                db.Project.DeleteObject(project);
                try
                {
                    db.SaveChanges();
                }
                catch (OptimisticConcurrencyException)
                {
                    db.Refresh(RefreshMode.ClientWins, project);
                    db.SaveChanges();
                }
            }
        }  
    }
}
